﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace SmartDatingService {
    public partial class ServicePrototype {
        public OperationStatus SendPM(string sessionKeyHash, Guid recipientId, string encryptedSubject, string encryptedText) {
            OperationStatus skResult = checkSessionKey(sessionKeyHash);
            if (skResult != OperationStatus.Success) return skResult;

            Entities contextEntities = new Entities();
            try {
                // check if the recipient exists
                IEnumerable<Membership> recipientMemberships =
                    from member in contextEntities.Memberships
                    where (member.usr_id == recipientId)
                    select member;
                if (recipientMemberships.Count() == 0)
                    return OperationStatus.NoRecipient;

                // decrypt the message
                byte[] sessionKey = sessionKeyByHash(sessionKeyHash);
                string subject = Encoding.Unicode.GetString(
                    CryptoImpl.decryptAes(b(encryptedSubject), sessionKey));
                string text = Encoding.Unicode.GetString(
                    CryptoImpl.decryptAes(b(encryptedText), sessionKey));
                DateTime dateSent = DateTime.UtcNow;

                // save it in the base
                // in "Sent" for the sender
                // in "Inbox for the receiver
                Guid senderId = userIdByHash(contextEntities, sessionKeyHash);
                contextEntities.Msgs.AddObject(new Msg() {
                    date_sent = dateSent,
                    folder_id = Convert.ToInt32(MessageFolder.Sent),
                    msg_id = Guid.NewGuid(),
                    msg_subject = subject,
                    msg_text = text,
                    msgbox_usr_id = senderId,
                    usr_from = senderId,
                    usr_to = recipientId
                });
                contextEntities.Msgs.AddObject(new Msg() {
                    date_sent = dateSent,
                    folder_id = Convert.ToInt32(MessageFolder.Inbox),
                    msg_id = Guid.NewGuid(),
                    msg_subject = subject,
                    msg_text = text,
                    msgbox_usr_id = recipientId,
                    usr_from = senderId,
                    usr_to = recipientId
                });

                contextEntities.SaveChanges();
            } catch (Exception) {
                return OperationStatus.Failure;
            } finally {
                contextEntities.Dispose();
            }

            return OperationStatus.Success;
        }

        public ResultWithStatus<List<Msg>> GetPMs(string sessionKeyHash, MessageFolder folder) {
            OperationStatus skResult = checkSessionKey(sessionKeyHash);
            if (skResult != OperationStatus.Success)
                return ResultWithStatus<List<Msg>>.NewErrorResult(skResult);

            Entities contextEntities = new Entities();
            try {
                // object data graph: eager load
                contextEntities.Msgs.Include("Membership");
                contextEntities.Msgs.Include("Membership.PersonalData");
                contextEntities.Msgs.Include("MembershipFrom");
                contextEntities.Msgs.Include("MembershipFrom.PersonalData");
                contextEntities.Msgs.Include("MembershipTo");
                contextEntities.Msgs.Include("MembershipTo.PersonalData");

                Guid userId = userIdByHash(contextEntities, sessionKeyHash);
                int folderId = Convert.ToInt32(folder);

                return ResultWithStatus<List<Msg>>.NewSuccess(
                    (from msg in contextEntities.Msgs
                     where (msg.msgbox_usr_id == userId &&
                     msg.folder_id == folderId)
                     orderby (msg.date_sent) descending
                     select msg).ToList());
            } catch (Exception) {
                return ResultWithStatus<List<Msg>>.NewErrorResult(OperationStatus.Failure);
            } finally {
                //contextEntities.Dispose();
            }
        }

        public ResultWithStatus<string> GetPMIds(string sessionKeyHash, MessageFolder folder) {
            ResultWithStatus<List<Msg>> resGet = GetPMs(sessionKeyHash, folder);
            if (resGet.Status != OperationStatus.Success) {
                return ResultWithStatus<string>.NewErrorResult(resGet.Status);
            }
            return ResultWithStatus<string>.NewSuccess(
                 String.Join(",", (from msg in resGet.Result
                                   select msg.msg_id.ToString()).ToArray())
                 );
        }

        public ResultWithStatus<Msg> GetPM(string sessionKeyHash, Guid messageId) {
            OperationStatus skResult = checkSessionKey(sessionKeyHash);
            if (skResult != OperationStatus.Success)
                return ResultWithStatus<Msg>.NewErrorResult(skResult);
            Entities contextEntities = new Entities();
            try {
                // object data graph: eager load
                contextEntities.Msgs.Include("Membership");
                contextEntities.Msgs.Include("Membership.PersonalData");
                contextEntities.Msgs.Include("MembershipFrom");
                contextEntities.Msgs.Include("MembershipFrom.PersonalData");
                contextEntities.Msgs.Include("MembershipTo");
                contextEntities.Msgs.Include("MembershipTo.PersonalData");

                Guid userId = userIdByHash(contextEntities, sessionKeyHash);

                return ResultWithStatus<Msg>.NewSuccess(
                    (from msg in contextEntities.Msgs
                     where (msg.msgbox_usr_id == userId &&
                     msg.msg_id == messageId)
                     select msg).First());
            } catch (Exception) {
                return ResultWithStatus<Msg>.NewErrorResult(OperationStatus.Failure);
            } finally {
                //contextEntities.Dispose();
            }
        }

        public OperationStatus MovePM(string sessionKeyHash, Guid messageId, MessageFolder newFolder) {
            // "Drafts" folder is not kept on the server for now ==>
            // operation not implemented, reserved for next version

            return OperationStatus.IllegalDestination;
        }

        public OperationStatus DeletePM(string sessionKeyHash, Guid messageId) {
            OperationStatus skResult = checkSessionKey(sessionKeyHash);
            if (skResult != OperationStatus.Success) return skResult;

            Entities contextEntities = new Entities();
            try {
                IEnumerable<Msg> foundMsgs =
                    from msg in contextEntities.Msgs
                    where (msg.msg_id == messageId)
                    select msg;
                if (foundMsgs.Count() == 0)
                    return OperationStatus.MessageNotFound;

                Msg messageToDelete = foundMsgs.First();
                contextEntities.Msgs.DeleteObject(messageToDelete);
                contextEntities.SaveChanges();

                return OperationStatus.Success;
            } catch (Exception) {
                return OperationStatus.Failure;
            } finally {
                contextEntities.Dispose();
            }
        }
    }
}